package com.xisoft.utils;

import org.apache.commons.lang3.StringUtils;
import sun.misc.BASE64Encoder;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * *
 *
 * @version 1.0<br>
 * @packagename: com.utils<br>
 * @author: LiBencheng<br>
 * @computer: licheng<br>
 * @date: Created on 2021/11/26$22:43<br>
 */
public class Fileutil {
    public static void deCompress(File file, String dest) throws IOException {
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dest));
        String dir = "";
        if (file.isDirectory()) {
            dir = file.getName();
        }
        zipFile(file, zos, dir);
    }

    public static void zipFile(File inFile, ZipOutputStream zos, String dir) throws IOException {
        byte[] buffer = new byte[2048];
        if (inFile.isDirectory()) {
            File[] files = inFile.listFiles();
            if (files == null || files.length == 0) {
                String entryName = dir + "/";
                zos.putNextEntry(new ZipEntry(entryName));
                return;
            }
            for (File file : files) {
                String entryName = dir + "/" + file.getName();
                if (file.isDirectory()) {
                    zipFile(file, zos, entryName);
                } else {
                    ZipEntry entry = new ZipEntry(entryName);
                    zos.putNextEntry(entry);
                    try (InputStream is = new FileInputStream(file)) {
                        // int len = 0;
                        // while ((len = is.read()) != -1)
                        // { zos.write(len); }
                        int len = 0;
                        while ((len = is.read(buffer)) != -1) {
                            zos.write(buffer, 0, len);
                        }
                    } catch (IOException e) {
                        throw e;
                    }
                }
            }
        } else {
            String entryName = dir + "/" + inFile.getName();
            ZipEntry entry = new ZipEntry(entryName);
            zos.putNextEntry(entry);
            try (InputStream is = new FileInputStream(inFile)) {
                int len = 0;
                while ((len = is.read()) != -1) {
                    zos.write(len);
                }
            } catch (IOException e) {
                throw e;
            }
        }
    }

    /**
     * *********************************************************** <br>
     * 说明： 罗列指定路径下的全部文件
     *
     * @param path
     * @return
     * @List<File>
     * @author licheng
     * @date Created on 2019-7-31
     * @time 下午1:02:22
     * @version 1.0 <br>
     * ************************************************************          <br>
     * @see
     */
    public final static List<File> listFile(String path) {
        File file = new File(path);
        return listFile(file);
    }

    /**
     * *********************************************************** <br>
     * 说明： 罗列指定路径下的全部文件
     *
     * @param path 需要处理的文件
     * @return 返回文件列表
     * @List<File>
     * @author licheng
     * @date Created on 2019-7-31
     * @time 下午1:02:39
     * @version 1.0 <br>
     * ************************************************************          <br>
     */
    public static List<File> listFile(File path) {
        List<File> list = new ArrayList<>();
        File[] files = path.listFiles();
        if (!ArrayUtil.isEmptyObj(files)) {
            for (File file : files) {
                if (file.isDirectory()) {
                    list.addAll(listFile(file));
                } else {
                    list.add(file);
                }
            }
        }
        return list;
    }

    /**
     * *********************************************************** <br>
     * 说明： 罗列指定路径下的全部文件
     *
     * @param path  指定的路径
     * @param child 是否罗列子目录
     * @return
     * @List<File>
     * @author licheng
     * @date Created on 2019-7-31
     * @time 下午1:04:37
     * @version 1.0 <br>
     * ************************************************************          <br>
     */
    public static List<File> listFile(File path, boolean child) {
        List<File> list = new ArrayList<>();
        File[] files = path.listFiles();
        if (!ArrayUtil.isEmptyObj(files)) {
            for (File file : files) {
                if (child && file.isDirectory()) {
                    list.addAll(listFile(file));
                } else {
                    list.add(file);
                }
            }
        }
        return list;
    }

    /**
     * *********************************************************** <br>
     * 说明：把对象从文件当中读出来 <br>
     *
     * @param filePatch
     * @return <br>
     * @Object <br>
     * @methods pers.bc.utils.file.StreamUtilbc#readObjFromFile <br>
     * @author LiBencheng <br>
     * @date Created on 2020-12-3 <br>
     * @time 20:19:52 <br>
     * @version 1.0 <br>
     * ************************************************************ <br>
     * @see <br>
     */
    public static Object readObjFromFile(String filePatch) {
        File file = new File(filePatch);
        if (!file.exists()) {
            return null;
        }

        Object obj = null;
        FileInputStream in = null;
        ObjectInputStream objIn = null;
        try {
            // 获取最后一个.的位置
            int lastIndexOf = file.getName().lastIndexOf(".");
            // 获取文件的后缀名 .data
            String suffix = file.getName().substring(lastIndexOf);
            if (!".data".equals(suffix)) {
                throw new RuntimeException("当前文件不是{[.data]}序列文件，不支持反序列化！");
            }

            in = new FileInputStream(file);
            objIn = new ObjectInputStream(in);
            obj = objIn.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            close(in, objIn);
        }

        return obj;
    }

    public static void close(Closeable... closeables) {
        try {
            for (Closeable closeable : closeables) {
                if (null != closeable) {
                    closeable.close();
                }
            }
        } catch (IOException ioe) {
        }
    }



    /**
     * 检查目录是否存在，不存在就新建
     *
     * @param filePath
     * @author lidf
     */
    public static void checkPath(String filePath) {
        String path = filePath.substring(0, filePath.lastIndexOf("/"));
        File dir = new File(path);
        if (!dir.exists()) {
            try {
                Files.createDirectories(Paths.get(path));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 压缩文件
     * @param sourceFile
     * @param zos
     * @param name
     * @param KeepDirStructure
     * @throws Exception
     * @author lidf
     */
    public static void compress(File sourceFile, ZipOutputStream zos, String name,
                                boolean KeepDirStructure, String targetFiles) throws Exception {
        byte[] buf = new byte[1024];
        if (sourceFile.isFile()) {
            if (StringUtils.isNotEmpty(targetFiles) && !targetFiles.contains(sourceFile.getName())){
                return;
            }
            // 向zip输出流中添加一个zip实体，构造器中name为zip实体的文件的名字
            zos.putNextEntry(new ZipEntry(name));
            // copy文件到zip输出流中
            int len;
            FileInputStream in = new FileInputStream(sourceFile);
            while ((len = in.read(buf)) != -1) {
                zos.write(buf, 0, len);
            }
            // Complete the entry
            zos.closeEntry();
            in.close();
        } else {
            File[] listFiles = sourceFile.listFiles();
            if (listFiles == null || listFiles.length == 0) {
                // 需要保留原来的文件结构时,需要对空文件夹进行处理
                if (KeepDirStructure) {
                    // 空文件夹的处理
                    zos.putNextEntry(new ZipEntry(name + "/"));
                    // 没有文件，不需要文件的copy
                    zos.closeEntry();
                }

            } else {
                for (File file : listFiles) {
                    // 判断是否需要保留原来的文件结构
                    if (KeepDirStructure) {
                        // 注意：file.getName()前面需要带上父文件夹的名字加一斜杠,
                        // 不然最后压缩包中就不能保留原来的文件结构,即：所有文件都跑到压缩包根目录下了
                        compress(file, zos, name + "/" + file.getName(), KeepDirStructure, targetFiles);
                    } else {
                        compress(file, zos, file.getName(), KeepDirStructure, targetFiles);
                    }

                }
            }
        }
    }

    /**
     * 文件名编码
     * @param agent
     * @param fileName
     * @return
     * @throws UnsupportedEncodingException
     * @author lidf
     */
    public static String encodeFileName(String agent, String fileName) throws UnsupportedEncodingException {
        if (agent.contains("MSIE")){
            fileName = URLEncoder.encode(fileName, "utf-8");
            fileName = fileName.replace("+", " ");
        }else if (agent.contains("Firefox")){
            BASE64Encoder base64Encoder = new BASE64Encoder();
            fileName = "=?utf-8?B?" + base64Encoder.encode(fileName.getBytes(StandardCharsets.UTF_8)) + "?=";

        }else {
            fileName = URLEncoder.encode(fileName, "utf-8");
        }
        return fileName;
    }

}
